﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;

namespace BookingEngine.Data
{
    public static class HotelReservationService
    {
        private static readonly string s_Url;
        private static readonly string s_UserName;
        private static readonly string s_Password;
        private static readonly string s_Iata;

        static HotelReservationService()
        {
            s_Url = string.IsNullOrEmpty(ConfigurationManager.AppSettings["FogXmlGatewayUrl"]) ? "http://sw.hubs1.net/servlet/SwitchReceiveServlet" : ConfigurationManager.AppSettings["FogXmlGatewayUrl"];
            s_UserName = string.IsNullOrEmpty(ConfigurationManager.AppSettings["FogXmlUserName"]) ? "DFBXML" : ConfigurationManager.AppSettings["FogXmlUserName"];
            s_Password = string.IsNullOrEmpty(ConfigurationManager.AppSettings["FogXmlPassword"]) ? "dB$15[46Xzi" : ConfigurationManager.AppSettings["FogXmlPassword"];
            s_Iata = string.IsNullOrEmpty(ConfigurationManager.AppSettings["FogXmlIata"]) ? "910000" : ConfigurationManager.AppSettings["FogXmlIata"];
        }

        #region 新预订

        /// <summary>
        /// </summary>
        /// <param name="language"> 语言种类(支持中英日文)，‘zh’,’en’,’jp’ </param>
        /// <param name="hotelCode"> FOG提供的酒店ID </param>
        /// <param name="outConfnum"> 外部订单号 </param>
        /// <param name="checkInDate"> 入住日期 </param>
        /// <param name="checkOutDate"> 离店日期 </param>
        /// <param name="roomCode"> 房型代码 </param>
        /// <param name="rateCode"> 价格代码 </param>
        /// <param name="roomsNumber"> 入住房间数 </param>
        /// <param name="adultsNumber"> 成人数 </param>
        /// <param name="childrenNumber"> 小孩数 </param>
        /// <param name="firstName"> 客人名 </param>
        /// <param name="lastName"> 客人姓 </param>
        /// <param name="guestName"> 其它客人名称 </param>
        /// <param name="otherGuestsNames"> 其他客人名数组 </param>
        /// <param name="phone"> 电话 </param>
        /// <param name="mobile"> 移动电话 </param>
        /// <param name="email"> 电子信箱 </param>
        /// <param name="street"> 所在街道 </param>
        /// <param name="holdTimeHour"> 客人最晚到店时间 (小时) </param>
        /// <param name="holdTimeMinute"> 客人最晚到店时间 (分) </param>
        /// <param name="contactName"> 联系人姓名 </param>
        /// <param name="contactPhone"> 联系人电话 </param>
        /// <param name="contactMobile"> 联系人手机 </param>
        /// <param name="contactEmail"> 联系人EMAIL </param>
        /// <param name="contactFax"> 联系人传真 </param>
        /// <param name="requirements"> 特称需求 </param>
        /// <param name="creditCardName"> 卡持有人名称 </param>
        /// <param name="creditCardType"> 卡类型 </param>
        /// <param name="creditCardNumber"> 卡号码 </param>
        /// <param name="creditCardExpiredMonth"> 信用卡有效日期 (月) </param>
        /// <param name="creditCardExpiredYear"> 信用卡有效日期 (年) </param>
        /// <param name="creditCardVerification"> 信用卡验证码 </param>
        /// <param name="remark"> 备注信息 </param>
        /// <param name="assuranceCode"> 担保 预付标识 </param>
        /// <param name="deliveryMode"> 发送模式 </param>
        /// <param name="rates"> 每日价 </param>
        /// <returns> </returns>
        public static string NewResv(string language, string hotelCode, string outConfnum, DateTime checkInDate, DateTime checkOutDate, string roomCode, string rateCode, int roomsNumber, int adultsNumber, int childrenNumber, string firstName, string lastName, string guestName, List<string> otherGuestsNames, string phone, string mobile, string email, string street, string holdTimeHour, string holdTimeMinute, string contactName, string contactPhone, string contactMobile, string contactEmail, string contactFax, List<string> requirements, string creditCardName, string creditCardType, string creditCardNumber, string creditCardExpiredMonth, string creditCardExpiredYear, string creditCardVerification, string remark, string assuranceCode, string deliveryMode, Dictionary<DateTime, Tuple<decimal, decimal>> rates)
        {
            if (string.IsNullOrEmpty(hotelCode))
            {
                throw new ArgumentNullException("hotelCode");
            }
            if (checkInDate.Date >= checkOutDate.Date)
            {
                throw new ArgumentOutOfRangeException("checkOutDate");
            }
            if (string.IsNullOrEmpty(roomCode))
            {
                throw new ArgumentNullException("roomCode");
            }
            if (string.IsNullOrEmpty(rateCode))
            {
                throw new ArgumentNullException("rateCode");
            }
            if (string.IsNullOrEmpty(firstName))
            {
                throw new ArgumentNullException("firstName");
            }
            if (string.IsNullOrEmpty(lastName))
            {
                throw new ArgumentNullException("lastName");
            }
            if (string.IsNullOrEmpty(mobile))
            {
                throw new ArgumentNullException("mobile");
            }
            if (string.IsNullOrEmpty(email))
            {
                throw new ArgumentNullException("email");
            }
            if (!string.IsNullOrEmpty(contactName))
            {
                if (string.IsNullOrEmpty(contactMobile))
                {
                    throw new ArgumentNullException("contactMobile");
                }
                if (string.IsNullOrEmpty(contactEmail))
                {
                    throw new ArgumentNullException("contactEmail");
                }
            }
            if (string.IsNullOrEmpty(assuranceCode))
            {
                throw new ArgumentNullException("assuranceCode");
            }
            if (string.IsNullOrEmpty(deliveryMode))
            {
                throw new ArgumentNullException("deliveryMode");
            }
            var requestBulider = new StringBuilder();
            requestBulider.Append(string.Format("<crsmessage PropID=\"{0}\" user=\"{1}\" pass=\"{2}\" msgtype=\"newresv\" language=\"{3}\">", hotelCode, s_UserName, s_Password, language));
            requestBulider.Append("<reservation>");
            requestBulider.Append(string.Format("<outconfnum>{0}</outconfnum>", outConfnum));
            requestBulider.Append(string.Format("<staydetail><date>{0}</date><nights>{1}</nights><roomtype>{2}</roomtype><rateclass>{3}</rateclass><rooms>{4}</rooms><adults>{5}</adults><children>{6}</children><channel>Website</channel></staydetail>", checkInDate.ToString("yyyy-MM-dd"), checkOutDate.Date.Subtract(checkInDate.Date).Days, roomCode, rateCode, roomsNumber, adultsNumber, childrenNumber));
            requestBulider.Append(string.Format("<guestinfo><firstname>{0}</firstname><lastname>{1}</lastname><guestname>{2}</guestname><otherguest>{3}</otherguest><phone>{4}</phone><mobile>{5}</mobile><email>{6}</email><street1>{7}</street1><holdTime>{8}:{9}:00</holdTime></guestinfo>", firstName, lastName, guestName, otherGuestsNames != null ? otherGuestsNames.Aggregate("", (s1, s2) => string.Format("{0},{1}", s1, s2)).Trim(',') : string.Empty, phone, mobile, email, street, holdTimeHour, holdTimeMinute));
            requestBulider.Append(string.Format("<contactinfo><name>{0}</name><phone>{1}</phone><mobile>{2}</mobile><email>{3}</email><fax>{4}</fax></contactinfo>", contactName, contactPhone, contactMobile, contactEmail, contactFax));
            if (requirements != null && requirements.Count > 0)
            {
                requestBulider.Append(string.Format("<specialrequirement><reqcode>{0}</reqcode></specialrequirement>", requirements.Aggregate("", (s1, s2) => string.Format("{0},{1}", s1, s2)).Trim(',')));
            }
            if (!string.IsNullOrEmpty(creditCardName))
            {
                if (string.IsNullOrEmpty(creditCardType))
                {
                    throw new ArgumentNullException("creditCardType");
                }
                if (string.IsNullOrEmpty(creditCardNumber))
                {
                    throw new ArgumentNullException("creditCardNumber");
                }
                if (string.IsNullOrEmpty(creditCardExpiredMonth))
                {
                    throw new ArgumentNullException("creditCardExpiredMonth");
                }
                if (string.IsNullOrEmpty(creditCardExpiredMonth))
                {
                    throw new ArgumentNullException("creditCardExpiredMonth");
                }
                if (string.IsNullOrEmpty(creditCardVerification))
                {
                    throw new ArgumentNullException("creditCardVerification");
                }
                requestBulider.Append(string.Format("<ccinfo><ccname>{0}</ccname><cctype>{1}</cctype><ccnum>{2}</ccnum><ccexp>{3}/{4}</ccexp><cvv>{5}</cvv></ccinfo>", creditCardName, creditCardType, creditCardNumber, creditCardExpiredMonth, creditCardExpiredYear, creditCardVerification));
            }
            requestBulider.Append(string.Format("<remarks><remark><![CDATA[{0}]]></remark><remark>[Booking from BOOKENGINE]</remark></remarks>", remark));
            requestBulider.Append(string.Format("<miscinfo><IATA>{0}</IATA></miscinfo>", s_Iata));
            requestBulider.Append(string.Format("<isassure>{0}</isassure>", assuranceCode));
            if (rates != null)
            {
                requestBulider.Append("<bookedrates>");
                foreach (var ratePair in rates)
                {
                    requestBulider.Append(string.Format("<bookedrate><date>{0}</date><rate>{1}</rate><extracharge>{2}</extracharge></bookedrate>", ratePair.Key.ToString("yyyy-MM-dd"), ratePair.Value.Item1.ToString("###0.00"), ratePair.Value.Item2.ToString("###0.00")));
                }
                requestBulider.Append("</bookedrates>");
            }
            requestBulider.Append(string.Format("<deliverymode>{0}</deliverymode>", deliveryMode));
            requestBulider.Append("</reservation>");
            requestBulider.Append("</crsmessage>");
            try
            {
                using (var webClient = new WebClient())
                {
                    webClient.Encoding = Encoding.UTF8;
                    return webClient.UploadString(s_Url, requestBulider.ToString());
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            return null;
        }

        #endregion

        #region 获取订单

        /// <summary>
        /// </summary>
        /// <param name="language"> 语言种类(支持中英日文)，‘zh’,’en’,’jp’ </param>
        /// <param name="confnum"> 订单号 </param>
        /// <returns> </returns>
        public static string GetResv(string language, string confnum)
        {
            if (string.IsNullOrEmpty(confnum))
            {
                throw new ArgumentNullException("confnum");
            }
            var requestBulider = new StringBuilder();
            requestBulider.Append(string.Format("<crsmessage user=\"{0}\" pass=\"{1}\" msgtype=\"getpropresv\" language=\"{2}\">", s_UserName, s_Password, language));
            requestBulider.Append("<resvuser />");
            requestBulider.Append(string.Format("<channel>{0}</channel>", "Website"));
            requestBulider.Append("<reservation>");
            requestBulider.Append(string.Format("<confnum>{0}</confnum>", confnum));
            requestBulider.Append(string.Format("<iata>{0}</iata>", s_Iata));
            requestBulider.Append("</reservation>");
            requestBulider.Append("</crsmessage>");
            try
            {
                using (var webClient = new WebClient())
                {
                    webClient.Encoding = Encoding.UTF8;
                    return webClient.UploadString(s_Url, requestBulider.ToString());
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            return null;
        }

        #endregion

        #region 取消订单

        /// <summary>
        /// </summary>
        /// <param name="language"> </param>
        /// <param name="hotelCode"> </param>
        /// <param name="confnum"> </param>
        /// <returns> </returns>
        public static string CancelResv(string language, string hotelCode, string confnum)
        {
            if (string.IsNullOrEmpty(hotelCode))
            {
                throw new ArgumentNullException("hotelCode");
            }
            if (string.IsNullOrEmpty(confnum))
            {
                throw new ArgumentNullException("confnum");
            }
            var requestBulider = new StringBuilder();
            requestBulider.Append(string.Format("<crsmessage PropID=\"{0}\" user=\"{1}\" pass=\"{2}\" msgtype=\"cancelresv\" language=\"{3}\">", hotelCode, s_UserName, s_Password, language));
            requestBulider.Append("<reservation>");
            requestBulider.Append(string.Format("<confnum>{0}</confnum>", confnum));
            requestBulider.Append("</reservation>");
            requestBulider.Append("</crsmessage>");
            try
            {
                using (var webClient = new WebClient())
                {
                    webClient.Encoding = Encoding.UTF8;
                    return webClient.UploadString(s_Url, requestBulider.ToString());
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            return null;
        }

        #endregion
    }
}